import PhysicsConstraints
import GameLogic as gl
import Scripts.Pathfinding as Pathfinding

class Behavior():
	"""Base Behavior Module - Should not be used directly, subclass it"""
	
	def __init__(self, cont):
		self.cont = cont
		own = self.cont.owner

		# Get the node mesh (we only have one option for now)
		self.nodes = Pathfinding.NodesFromFile('NODEMESH.dat')
		
		# Get a list of the checkpoints
		scene = gl.getCurrentScene()
		self.checkpoints = [ob for ob in scene.objects if ob.name.startswith("OBCheckpoint")]
		
		# Props to keep track of checkpoints and laps
		self.cps = []
		self.laps = 0
		
		# XXX Setting the max laps here for now, should be done by the map
		import GameLogic
		if not hasattr(GameLogic, 'maxlaps'):
			GameLogic.maxlaps = 3
			GameLogic.laps = 0
		
		# Get the object to use for actions:
		self.actionOb = own["actionOb"]
		
		# Create the constraint
		pid = own.getPhysicsId()
		
		constraint = PhysicsConstraints.createConstraint(pid, 0, 11)
		cid = constraint.getConstraintId()
		
		vid = PhysicsConstraints.getVehicleConstraint(cid)
		
		# Set the kart's mass
		own.mass = own["Mass"]
		
		# Store the vehicle id
		own["VehicleID"] = vid
		
		# Setup the tires
		objList = gl.getCurrentScene().objects
		
		for x in range(1, 5):
			i = str(x)	
			
			# Add the wheel
			vid.addWheel(
					# Name
					objList["OB"+own["Tire_"+i+"_Name"]],
					
					# Position
					self.CalcLocalPosition(objList["OB"+own["Tire_"+i+"_Name"]], own),
					
					# Suspension Angle
					own["Tire_"+i+"_SuspensionAngle"],
					
					# Axis
					own["Tire_"+i+"_Axis"],
					
					# Suspension
					own["Tire_"+i+"_Suspension"],
					
					# Radius
					own["Tire_"+i+"_Radius"],
					
					# Steerable
					own["Tire_"+i+"_Steerable"])
			
			# Now lets change some settings
			vid.setTyreFriction(own["Tire_"+i+"_Grip"], x-1)
			vid.setSuspensionCompression(own["Tire_"+i+"_SuspensionCompression"], x-1)
			vid.setSuspensionDamping(own["Tire_"+i+"_SuspensionDamping"], x-1)
			vid.setSuspensionStiffness(own["Tire_"+i+"_SuspensionStiffness"], x-1)
			vid.setRollInfluence(own["Tire_"+i+"_RollInfluence"], x-1)
			
		# Store some settings
		self.vid = own["VehicleID"]
		self.gasPower = own["GasPower"]
		self.reversePower = own["ReversePower"]
		self.brakePower = own["BrakePower"]
		self.ebrakePower = own["EBrakePower"]
		self.turnPower = own["TurnPower"]
		
	def CalcLocalPosition(self, local, parent):
		x = local.worldPosition[0] - parent.worldPosition[0]
		y = local.worldPosition[1] - parent.worldPosition[1]
		z = local.worldPosition[2] - parent.worldPosition[2]

		return [x, y, z]
	
	def main(self):
		pass
		
	def Move(self, trigger, factor):
		"""This handles Gas/Reverse"""
		
		power = 0

		# Reverse is done with a negative factor
		
		if trigger:
			if factor > 0:
				power = (-self.gasPower) * factor
			else:
				power = self.reversePower * (-factor)
		
		self.vid.applyEngineForce(power, 0)
		self.vid.applyEngineForce(power, 1)
		self.vid.applyEngineForce(power, 2)
		self.vid.applyEngineForce(power, 3)
		
		
	def Brake(self, trigger, factor):
		"""This handles brake and ebrake"""
		
		frontBrake = 0
		rearBrake = 0
		
		if trigger:
			frontBrake = self.brakePower * factor
			rearBrake = self.brakePower * factor
			
		# ebrake not implemented yet, could be done with a factor
			
		self.vid.applyBraking(frontBrake, 0)
		self.vid.applyBraking(frontBrake, 1)
		self.vid.applyBraking(rearBrake, 2)
		self.vid.applyBraking(rearBrake, 3)
		
	def Turn(self, trigger, factor):
		"""This handles left/right steering"""
		
		own = self.cont.owner
		turn = 0
		
		# Positive is left, negative is right
		
		if trigger:
			turn = self.turnPower * factor
			
		# We need to figure out which tires turn
		
		for x in range(1, 5):
			i = str(x)
			if own["Tire_"+i+"_Steerable"]:
				self.vid.setSteeringValue(turn, x-1)
		
	def PlayActions(self, gas, reverse, brake, ebrake, left, right):
		def play(action):
			gl.sendMessage(action, '', self.actionOb)
		
		if left:
			play('Left')
		elif right:
			play('Right')
		else:
			play('Idle')
		
	def ResetPosition(self):
		from Mathutils import RotationMatrix
		ob = self.cont.owner
		node = Pathfinding.GetNearestNode(ob.worldPosition, self.nodes)
		next = Pathfinding.GetNextNode(node, self.nodes)
		
		angle = Pathfinding.GetAngleToNode(ob, next)		
		
		ob.worldOrientation = RotationMatrix(angle, 3, "z")
		ob.worldPosition = node.position
		ob.setLinearVelocity((0, 0, 0), 1)
		